﻿using System;
using System.Linq;
using System.Web;
using System.Web.UI;
using Fotofly;
using umbraco;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic;
using umbraco.cms.businesslogic.media;

namespace Cultiv.PhotoMetaData
{
    public class CreateMetaData : ApplicationBase
    {
        public CreateMetaData()
        {
            Media.AfterSave += CreateMediaMetaData;
        }

        private static void CreateMediaMetaData(Media sender, SaveEventArgs e)
        {
            if (sender.ContentType.Alias != "Image") return;
            if (sender.getProperty("overwriteMetaData") == null || sender.getProperty("overwriteMetaData").Value.ToString() == "0") return;

            var filePath = HttpContext.Current.Server.MapPath(ConstructRelativeDestPath(sender.getProperty("umbracoFile").Value.ToString()));
            var photo = new JpgPhoto(filePath);
            photo.ReadMetadata();
            var metadata = photo.Metadata;

            var properties = sender.getProperties;
            foreach (var propType in properties.Select(property => property.PropertyType))
            {
                switch (propType.Alias)
                {
                    case "addressOfGpsLookupDate":
                        SetProperty(sender, propType.Alias, metadata.AddressOfGpsLookupDate.ToString());
                        break;
                    case "addressOfGpsSource":
                        SetProperty(sender, propType.Alias, metadata.AddressOfGpsSource);
                        break;
                    case "addressOfLocationCreatedAddressLine":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.AddressLine);
                        break;
                    case "addressOfLocationCreatedCity":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.City);
                        break;
                    case "addressOfLocationCreatedCountry":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.Country);
                        break;
                    case "addressOfLocationCreatedHierarchicalCountryRegionCity":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.HierarchicalCountryRegionCity);
                        break;
                    case "addressOfLocationCreatedHierarchicalName":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.HierarchicalName);
                        break;
                    case "addressOfLocationCreatedIsCompleteAddress":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.IsCompleteAddress.ToString());
                        break;
                    case "addressOfLocationCreatedIsValidAddress":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.IsValidAddress.ToString());
                        break;
                    case "addressOfLocationCreatedParts":
                        var locationCreatedParts = metadata.AddressOfLocationCreated.Parts.Aggregate(string.Empty, (current, part) => current == string.Empty ? part : current + ", " + part);
                        SetProperty(sender, propType.Alias, locationCreatedParts);
                        break;
                    case "addressOfLocationCreatedRegion":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.Region);
                        break;
                    case "addressOfLocationCreatedShortName":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationCreated.ShortName);
                        break;
                    case "addressOfLocationShownAddressLine":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.AddressLine);
                        break;
                    case "addressOfLocationShownCity":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.City);
                        break;
                    case "addressOfLocationShownCountry":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.Country);
                        break;
                    case "addressOfLocationShownHierarchicalCountryRegionCity":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.HierarchicalCountryRegionCity);
                        break;
                    case "addressOfLocationShownHierarchicalName":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.HierarchicalName);
                        break;
                    case "addressOfLocationShownIsCompleteAddress":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.IsCompleteAddress.ToString());
                        break;
                    case "addressOfLocationShownIsValidAddress":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.IsValidAddress.ToString());
                        break;
                    case "addressOfLocationShownParts":
                        var locationShownParts = metadata.AddressOfLocationShown.Parts.Aggregate(string.Empty, (current, part) => current == string.Empty ? part : current + ", " + part);
                        SetProperty(sender, propType.Alias, locationShownParts);
                        break;
                    case "addressOfLocationShownRegion":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.Region);
                        break;
                    case "addressOfLocationShownShortName":
                        SetProperty(sender, propType.Alias, metadata.AddressOfLocationShown.ShortName);
                        break;
                    case "aperture":
                        SetProperty(sender, propType.Alias, metadata.Aperture.ToString());
                        break;
                    case "authors":
                        var authors = metadata.Authors.Aggregate(string.Empty, (current, auth) => current == string.Empty ? auth : current + ", " + auth);
                        SetProperty(sender, propType.Alias, authors);
                        break;
                    case "cameraManufacturer":
                        SetProperty(sender, propType.Alias, metadata.CameraManufacturer);
                        break;
                    case "cameraModel":
                        SetProperty(sender, propType.Alias, metadata.CameraModel);
                        break;
                    case "comment":
                        SetProperty(sender, propType.Alias, metadata.Comment);
                        break;
                    case "copyright":
                        SetProperty(sender, propType.Alias, metadata.Copyright);
                        break;
                    case "creationSoftware":
                        SetProperty(sender, propType.Alias, metadata.CreationSoftware);
                        break;
                    case "dateAquired":
                        SetProperty(sender, propType.Alias, metadata.DateAquired.ToString());
                        break;
                    case "dateDigitised":
                        SetProperty(sender, propType.Alias, metadata.DateDigitised.ToString());
                        break;
                    case "dateModified":
                        SetProperty(sender, propType.Alias, metadata.DateModified.ToString());
                        break;
                    case "dateTaken":
                        SetProperty(sender, propType.Alias, metadata.DateTaken.ToString());
                        break;
                    case "description":
                        SetProperty(sender, propType.Alias, metadata.Description);
                        break;
                    case "dateUtc":
                        SetProperty(sender, propType.Alias, metadata.DateUtc.ToString());
                        break;
                    case "digitalZoomRatio":
                        SetProperty(sender, propType.Alias, metadata.DigitalZoomRatio.ToString());
                        break;
                    case "exposureBias":
                        SetProperty(sender, propType.Alias, metadata.ExposureBias.ToString());
                        break;
                    case "focalLength":
                        SetProperty(sender, propType.Alias, metadata.FocalLength);
                        break;
                    case "gpsPositionOfLocationCreatedAltitude":
                        SetProperty(sender, propType.Alias, metadata.GpsPositionOfLocationCreated.Altitude.ToString());
                        break;
                    case "gpsPositionOfLocationCreatedDimension":
                        SetProperty(sender, propType.Alias, metadata.GpsPositionOfLocationCreated.Dimension.ToString());
                        break;
                    case "gpsPositionOfLocationCreatedIsValidCoordinate":
                        SetProperty(sender, propType.Alias, metadata.GpsPositionOfLocationCreated.IsValidCoordinate.ToString());
                        break;
                    case "gpsPositionOfLocationCreatedLongitude":
                        SetProperty(sender, propType.Alias, metadata.GpsPositionOfLocationCreated.Longitude.ToString());
                        break;
                    case "gpsPositionOfLocationCreatedLatitude":
                        SetProperty(sender, propType.Alias, metadata.GpsPositionOfLocationCreated.Latitude.ToString());
                        break;
                    case "gpsPositionOfLocationCreatedSatelliteTime":
                        SetProperty(sender, propType.Alias, metadata.GpsPositionOfLocationCreated.SatelliteTime.ToString());
                        break;
                    case "gpsPositionOfLocationCreatedSource":
                        SetProperty(sender, propType.Alias, metadata.GpsPositionOfLocationCreated.Source);
                        break;
                    case "horizontalResolution":
                        SetProperty(sender, propType.Alias, metadata.HorizontalResolution.ToString());
                        break;
                    case "imageHeight":
                        SetProperty(sender, propType.Alias, metadata.ImageHeight.ToString());
                        break;
                    case "imageWidth":
                        SetProperty(sender, propType.Alias, metadata.ImageWidth.ToString());
                        break;
                    case "isOriginalCameraDateSet":
                        SetProperty(sender, propType.Alias, metadata.IsOriginalCameraDateSet.ToString());
                        break;
                    case "isoSpeed":
                        SetProperty(sender, propType.Alias, metadata.IsoSpeed.ToString());
                        break;
                    case "isUtcDateSet":
                        SetProperty(sender, propType.Alias, metadata.IsUtcDateSet.ToString());
                        break;
                    case "meteringMode":
                        SetProperty(sender, propType.Alias, metadata.MeteringMode.ToString());
                        break;
                    case "microsoftRegionInfo":
                        SetProperty(sender, propType.Alias, metadata.MicrosoftRegionInfo.ToString());
                        break;
                    case "orientation":
                        SetProperty(sender, propType.Alias, metadata.Orientation.ToString());
                        break;
                    case "originalCameraDate":
                        SetProperty(sender, propType.Alias, metadata.OriginalCameraDate.ToString());
                        break;
                    case "originalCameraFilename":
                        SetProperty(sender, propType.Alias, metadata.OriginalCameraFilename);
                        break;
                    case "people":
                        var people = metadata.People.Aggregate(string.Empty, (current, person) => current == string.Empty ? person : current + ", " + person);
                        SetProperty(sender, propType.Alias, people);
                        break;
                    case "rating":
                        SetProperty(sender, propType.Alias, metadata.Rating.ToString());
                        break;
                    case "shutterSpeed":
                        SetProperty(sender, propType.Alias, metadata.ShutterSpeed.ToString());
                        break;
                    case "subject":
                        SetProperty(sender, propType.Alias, metadata.Subject);
                        break;
                    case "tags":
                        SetProperty(sender, propType.Alias, metadata.Tags.ToString());
                        break;
                    case "utcOffset":
                        SetProperty(sender, propType.Alias, metadata.UtcOffset.ToString());
                        break;
                    case "verticalResolution":
                        SetProperty(sender, propType.Alias, metadata.VerticalResolution.ToString());
                        break;
                }
            }

            sender.getProperty("overwriteMetaData").Value = "0";

            ((Page)HttpContext.Current.Handler).Items.Add("imageNodeUrl", HttpContext.Current.Request.Url.ToString());
            ((Page)HttpContext.Current.Handler).PreRender += ImagePreRender;
        }

        private static void SetProperty(Content media, string propertyAlias, string propertyValue)
        {

            if (media.getProperty(propertyAlias).Value.ToString() != ""
                    && (media.getProperty("overwriteMetaData") == null || media.getProperty("overwriteMetaData").Value.ToString() != "1")
                ) return;

            if (propertyValue == "NaN")
                propertyValue = "";

            media.getProperty(propertyAlias).Value = propertyValue ?? "";
        }

        private static string ConstructRelativeDestPath(string mediaFilename)
        {
            const string mediaPath = "~/";
            if (UmbracoSettings.UploadAllowDirectories)
            {
                var path = VirtualPathUtility.Combine(mediaPath, mediaFilename);
                return VirtualPathUtility.ToAbsolute(path);
            }

            return VirtualPathUtility.ToAbsolute(mediaFilename);
        }

        private static void ImagePreRender(object sender, EventArgs e)
        {
            if (((Page)HttpContext.Current.Handler).Items.Contains("imageNodeUrl") && !string.IsNullOrEmpty((string)((Page)HttpContext.Current.Handler).Items["imageNodeUrl"]))
                HttpContext.Current.Response.Redirect((string)((Page)HttpContext.Current.Handler).Items["imageNodeUrl"]);
        }
    }
}